#ifndef _FEATURE_CLASS_DESC_H_
#define _FEATURE_CLASS_DESC_H_

#include <config.h>
#include <GSTenums.h>
#include <buildspec.h>
#include <exceptions/GSTRuntimeException.h>
#include <Geometry/SRSItem.h>
#include <Client/ClientUtils/Network/NetworkInterfaceStructs.h>
#include <Client/ClientUtils/Network/TableAttributeDesc.h>
#include <Client/ClientUtils/Network/ObjectPropertyDesc.h>
#include <Client/ClientUtils/Network/SimplexPropertyDesc.h>
#include <Client/ClientUtils/Network/TableConstrainedAttributeDesc.h>
#include <Geometry/IGeometry.h>

using GST::Geometry::PropertyAlignments;
using GST::Geometry::IGeometry;

#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp> 
#include <boost/optional.hpp>
#include <Geometry/boost_serialize_includes.hpp>

namespace GST {

	//exceptions:
		//see below the class

namespace ClientUtils {

	/**
	 * A special TableAttributeDesc
	 */
class GST_API_EXPORT GeoColumnDesc
	: public TableAttributeDesc
{	
	friend class boost::serialization::access;

public:
	typedef PropertyAlignments PropertyAlignment;

	GeoColumnDesc(const std::string& name, const std::string& fullFeatureClassName, const IGeometry::GeometryType & geometryType, Geometry::SRSPtr srs = Geometry::SRSPtr(), const PropertyAlignment& alignment = Geometry::VERTEX_ALIGNED, const std::string propertyTable = "");

	///@name getters
	//@{
			///returns (unquoted) the table name
		std::string getPropertyTableName() const;
			///returns (unquoted) schema.tablename
		std::string getFullPropertyTableName() const;
		void setPropertyTableName(const std::string & tableName);
		std::string getGeometryTypeAsDDL() const;
		std::string getPropertyAlignmentAsDDL() const;

		GST::ClientUtils::GeoColumnDesc::PropertyAlignment getAlignment() const;
		void setAlignment(GST::ClientUtils::GeoColumnDesc::PropertyAlignment val);
		IGeometry::GeometryType getGeometryType() const;
		void setGeometryType(IGeometry::GeometryType val);
		GST::Geometry::SRSPtr getSrs() const;
		void setSrs(GST::Geometry::SRSPtr val);
	//@}

protected:
	IGeometry::GeometryType geomtype;
	PropertyAlignment alignment;
	std::string propertyTableName;
	Geometry::SRSPtr srs;

	GeoColumnDesc()
		: TableAttributeDesc()
	{						
	}

private:
	template <typename Archive> 
	void serialize(Archive &ar, const unsigned int version) 
	{ 
		ar & boost::serialization::make_nvp("columnDesc", boost::serialization::base_object<TableAttributeDesc>(*this) ); 
		//If you change members here do not forget to increment object version (see bottom of this file)
		ar & boost::serialization::make_nvp("geomtype",this->geomtype); 
		ar & boost::serialization::make_nvp("alignment",this->alignment);
		ar & boost::serialization::make_nvp("propertyTableName",this->propertyTableName); 
		ar & boost::serialization::make_nvp("srs",this->srs);
	} 

};
typedef boost::shared_ptr<GeoColumnDesc> GeoColumnDescPtr;

//-------------------------- class of headerfile --------------------------------

	/**
	 * A detailed description of a feature class 
	 */
class GST_API_EXPORT FeatureClassDetailedDesc
{
	friend class boost::serialization::access; 

protected:
	std::string name;
	GeoColumnDescPtr geometryColumn;
	std::string owner;
	ObjectPropertyDescListPtr objectProperties;
	PropertyAliasMapPtr objectPropertyAliases;
	SimplexPropertyDescListPtr simplexProperties;
	PropertyAliasMapPtr simplexPropertyAliases;
	int numberOfFeatures;
    long long id;
	ZAxisDomain zAxisDomain;
	
public:
	FeatureClassDetailedDesc();

	FeatureClassDescPtr getSimpleDesc() const;
	bool isPublic() const;
	void setGroup(const std::string & group);
	std::string getGroup() const;
	std::string getFullName() const;

	std::string getName() const;
	void setName(std::string val);
	GST::ClientUtils::GeoColumnDescPtr getGeometryColumn() const;
	void setGeometryColumn(GST::ClientUtils::GeoColumnDescPtr val);
	std::string getOwner() const;
	void setOwner(std::string val);
	ObjectPropertyDescListPtr getObjectProperties() const;
	void setObjectProperties(ObjectPropertyDescListPtr val);
	SimplexPropertyDescListPtr getSimplexProperties() const;
	void setSimplexProperties(SimplexPropertyDescListPtr val);
	PropertyAliasMapPtr getObjectPropertyAliases() const;
	void setObjectPropertyAliases(PropertyAliasMapPtr val);
	PropertyAliasMapPtr getSimplexPropertyAliases() const;
	void setSimplexPropertyAliases(PropertyAliasMapPtr val);
	int getNumberOfFeatures() const;
	void setNumberOfFeatures(int val);
    long long getID() const;
    void setID(const long long val);
	ZAxisDomain getZAxisDomain() const;
	void setZAxisDomain(ZAxisDomain zAxisDomain);
	
	boost::optional<PropertyAlias> getPropertyAlias( const ObjectPropertyDesc & objProp );
	boost::optional<PropertyAlias> getPropertyAlias( const SimplexPropertyDesc & simplexProp );

private:
	template <typename Archive> 
	void serialize(Archive &ar, const unsigned int version) 
	{ 
		if(version < 2) {
			throw exceptions::GSTRuntimeException(__METHOD_NAME__, "Can not read class FeatureClassDetailedDesc below version 2.");
		}

		//If you change members here do not forget to increment object version (see bottom of this file)
		ar & boost::serialization::make_nvp("name",this->name); 
		ar & boost::serialization::make_nvp("geometryColumn",this->geometryColumn);
		ar & boost::serialization::make_nvp("owner",this->owner); 		
        // removing m_shape before serializing object properties and readding it afterwards
        ObjectPropertyDescList::iterator it = this->objectProperties->find("m_shape");
        const bool found = (it != this->objectProperties->end());
		ObjectPropertyDescPtr m_shape;
        if ( found )
        {
			m_shape = it->second;
            this->objectProperties->erase(it);
        }
		ar & boost::serialization::make_nvp("objectProperties",this->objectProperties);
        // readding m_shape to object properties again
        if ( found ) {
            (*this->objectProperties)["m_shape"] = m_shape;
        }
		ar & boost::serialization::make_nvp("simplexProperties",this->simplexProperties);

		if(version >= 3) {
			ar & boost::serialization::make_nvp("objectPropertyAliases",this->objectPropertyAliases);
			ar & boost::serialization::make_nvp("simplexPropertyAliases",this->simplexPropertyAliases);
		}
        if(version >= 4) {
            ar & boost::serialization::make_nvp("id",this->id);
        }
		if(version >= 5)
		{
			ar &boost::serialization::make_nvp("zAxisDomain", this->zAxisDomain);
		}
	} 
};
typedef boost::shared_ptr<FeatureClassDetailedDesc>  FeatureClassDetailedDescPtr;
typedef std::vector<FeatureClassDetailedDescPtr> FeatureClassDetailedDescList;
typedef boost::shared_ptr<FeatureClassDetailedDescList> FeatureClassDetailedDescListPtr;

}// namespace ClientUtils
}// namespace GST

BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::GeoColumnDesc);
BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::FeatureClassDetailedDesc);

BOOST_CLASS_VERSION(GST::ClientUtils::GeoColumnDesc, 1)
BOOST_CLASS_VERSION(GST::ClientUtils::FeatureClassDetailedDesc, 5)

#endif  //_FEATURE_CLASS_DESC_H_
